
namespace SharpTalk.Client.Services
{
    using System;
    using System.Diagnostics;
    using System.Reflection;
    using System.Runtime.Remoting.Messaging;
    using System.ServiceModel;
    using Core.Delegates;
    using Core.Diagnostic;
    using Core.Services.Contracts.Client;
    using Core.Services.Requests;
    using Core.Services.Responses;

    [ServiceBehavior(Namespace = "http://SharpTalk/", ConcurrencyMode = ConcurrencyMode.Multiple, InstanceContextMode = InstanceContextMode.Single)]
    public sealed class MessageServices
        : Traceable, IMessageServices
    {
        public event EventHandler<MessageEventArgs> MessageReceived;

        public MessageServices()
        {
        }

        public MessageServices(ITraceProvider traceProvider)
        {
            TraceProvider = traceProvider;
        }

        private MessageSendResponse DeliverMessage(MessageSendRequest request)
        {
            if (ShouldTrace(TraceEventType.Verbose)) TraceMethodCall(MethodBase.GetCurrentMethod());
            InvokeMessageReceived(new MessageEventArgs(request.Content));
            return new MessageSendResponse(){ Content = true };
        }

        public IAsyncResult BeginDeliverMessage(MessageSendRequest request, AsyncCallback callback, object state)
        {
            if (ShouldTrace(TraceEventType.Verbose)) TraceMethodCall(MethodBase.GetCurrentMethod());
            var del = new RequestDelegate<MessageSendRequest, MessageSendResponse>(DeliverMessage);
            return del.BeginInvoke(request, callback, state);
        }
        public MessageSendResponse EndDeliverMessage(IAsyncResult result)
        {
            if (ShouldTrace(TraceEventType.Verbose)) TraceMethodCall(MethodBase.GetCurrentMethod());
            var res = (AsyncResult)result;
            var response = ((RequestDelegate<MessageSendRequest, MessageSendResponse>)res.AsyncDelegate).EndInvoke(result);
            res.AsyncWaitHandle.Close();
            return response;
        }

        private void InvokeMessageReceived(MessageEventArgs e)
        {
            if (ShouldTrace(TraceEventType.Verbose)) TraceMethodCall(MethodBase.GetCurrentMethod());
            var handler = MessageReceived;
            if (handler != null) handler(this, e);
        }
    }
}